工厂模式(Factory Pattern)

概述

工厂模式(Factory Pattern)是Java中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。建立一个工厂来创建对象,你可以轻松方便地构造对象实例,而不必关心构造对象实例的细节和复杂过程

  1. 还没有工厂时代:假如还没有工厂,如果一个客户要一辆车,做法是客户去创建一辆车,然后拿来用。当然通过接口客户可以创建不同的车,比如奥迪,比亚迪,奔驰。
  2. 简单工厂模式时代:有了工厂之后,用户不用去自己创建汽车,由一个工厂来帮他创建汽车。想要什么车,这个工厂就可以建什么车。比如:想要奥迪,工厂就创建奥迪;想要比亚迪,工厂就创建比亚迪;想要奔驰,工厂就创建奔驰。即所有品牌的车都由一个工厂创建。
  3. 工厂方法模式时代:随着工厂及客户需求的壮大,生产的车的品牌越来越多,比如,又加了保时捷,法拉利等品牌。这时在同一个工厂生产这些车十分的麻烦,于是由单独分出来多个具体的工厂,只生产一种品牌的车。每个具体工厂创建一种品牌的车,即具体工厂类只能创建一个具体产品。但是原先生产车的那个工厂是个抽象,需要指定某个具体的工厂才能生产出相应品牌的车。
  4. 抽象工厂模式时代:还是来谈谈车,在每个品牌的车中都分高配和低配,高配的车引擎,座椅,轮胎方面都有别于低配。这时工厂要生产这两种类型的车,每种类型的车必须使用对应的引擎,座椅,轮胎,如:高配的车必须使用高级的引擎,高级的座椅,高级的轮胎;低配的车使用低级的引擎,低级的座椅,低级的轮胎。这时候生产某个品牌的车的工厂又分出了两个工厂,分别用于生产高配的车,和低配的车。

分类

工厂模式可以分为三类:

  1. 简单工厂模式(Simple Factory)
  2. 工厂方法模式(Factory Method)
  3. 抽象工厂模式(Abstract Factory)

三种模式从上到下逐步抽象,并且更具一般性。

GOF在《设计模式》一书中将工厂模式分为两类:工厂方法模式(Factory Method)与抽象工厂模式(Abstract Factory)。将简单工厂模式(Simple Factory)看为工厂方法模式的一种特例,两者归为一类。

三种模式的具体实现

简单工厂模式(Simple Factory)

  • 简单工厂模式又称静态工厂方法模式,因为工厂类中的方法是静态方法,前面加有static。
  • 简单工厂模式提供了三种实现方式,其中第三种方式采用反射实现解决了前两种方式——每次增加一个产品时,都需要增加一个具体类和对象实现工厂(在工厂中需追加代码来实例化追加类所对应的对象),这一缺点。

备注:

静态方法与普通方法的区别:

static方法可以通过类名访问,也可以通过类的实例访问。

static方法不能访问类中非static的数据。

比如:

class A
{
static void F(){};
}

在main函数中可以

A a;

a.F();

也可以

A.F()

普通方法又叫实例方法,只能通过类的实例访问。

他只能a.F();

类图

代码

产品接口:

  • 抽象产品角色:它一般是具体产品继承的父类或者实现的接口。
package com.match.factory.simplefactory;

public interface Car
{
void run();
}

具体产品类:

  • 具体产品角色:工厂类所创建的对象就是此角色的实例。在java中由一个具体类实现。
//奥迪
package com.match.factory.simplefactory;

public class Audi implements Car
{
@Override
public void run()
{
System.out.println("奥迪出发");
}
}

//奔驰
package com.match.factory.simplefactory;

public class Benz implements Car
{

@Override
public void run()
{
System.out.println("奔驰出发");
}

}

//比亚迪
package com.match.factory.simplefactory;

public class Byd implements Car
{
@Override
public void run()
{
System.out.println("比亚迪出发");
}
}

三种工厂类:

  • 工厂类角色:这是本模式的核心,含有一定的商业逻辑和判断逻辑。
//工厂1
package com.match.factory.simplefactory;

public class CarFactory1
{
public static Car createCar(String Type)
{
if("Audi".equals(Type))
{
return new Audi();
}
else if("Byd".equals(Type))
{
return new Byd();
}
else if("Benz".equals(Type))
{
return new Benz();
}
else
{
return null;
}
}
}

//工厂2
package com.match.factory.simplefactory;

public class CarFactory2
{
public static Car createAudi()
{
return new Audi();
}
public static Car createByd()
{
return new Byd();
}
public static Car createBenz()
{
return new Benz();
}
}

//工厂3
package com.match.factory.simplefactory;

public class CarFactory3
{
public static Car createCar(Class<? extends Car> cls)
{
Car car = null;
try
{
car = (Car) Class.forName(cls.getName()).newInstance();
} catch (InstantiationException e)
{
e.printStackTrace();
} catch (IllegalAccessException e)
{
e.printStackTrace();
} catch (ClassNotFoundException e)
{
e.printStackTrace();
}
return car;
}
}

测试代码:

package com.match.factory.simplefactory;

public class Client
{
public static void main(String[] args)
{
test1();
}
/**
* 测试CarFactory1
*/
public static void test1()
{
Car c1 = CarFactory1.createCar("Audi");
Car c2 = CarFactory1.createCar("Byd");
Car c3 = CarFactory1.createCar("Benz");
c1.run();
c2.run();
c3.run();
}
/**
* 测试CarFactory2
*/
public static void test2()
{
Car c1 = CarFactory2.createAudi();
Car c2 = CarFactory2.createByd();
Car c3 = CarFactory2.createBenz();
c1.run();
c2.run();
c3.run();
}
/**
* 测试CarFactory3
*/
public static void test3()
{
Car c1 = CarFactory3.createCar(Audi.class);
Car c2 = CarFactory3.createCar(Byd.class);
Car c3 = CarFactory3.createCar(Benz.class);
c1.run();
c2.run();
c3.run();
}
}

总结

总结之前先了解下面向对象设计的基本原则:

  • OCP(开闭原则,Open-Closed Principle):一个软件的实体应当对扩展开放,对修改关闭。也就是说,对于一个已有软件,如果需要扩展,应当在不需修改已有代码的基础上进行。
  • DIP(依赖反转原则,Dependence Inversion Principle)要针对接口编程,不要针对实现编程。也就是说,对于不同层次的编程,高层次暴露给低层次。
  • LOD(迪米特法则,Law of Demeter):只与你直接的朋友通信,而避免与陌生人通信。也就是说,一个软件实体应当尽可能少的与其他实体发生相互作用。

现在我们来谈谈简单工厂模式的优缺点:

优点:

  • 客户端与产品没有直接建立联系,即调用者没有直接依赖于被调用者,当Audi类,Byd类修改后,不需要对其进行修改。

缺点:

  • 每增加一种新型车,都要在工厂类中增加相应的创建业务逻辑,这显然是违背了开闭原则。

虽然,我们在第三种方式中解决了简单工厂模式的缺点,不过还有一种方式来解决,那就是工厂方法了,注意工厂方法中没有静态方法。

工厂方法模式(Factory Method)

类图

代码

产品接口:

  • 抽象产品角色:它是具体产品继承的父类或者是实现的接口。在java中一般有抽象类或者接口来实现。
package com.match.factory.factorymethod;

public interface Car
{
void run();
}

具体产品类:

  • 具体产品角色:具体工厂角色所创建的对象就是此角色的实例。在java中由具体的类来实现。
package com.match.factory.factorymethod;

public class Audi implements Car
{
@Override
public void run()
{
System.out.println("奥迪出发");
}
}

package com.match.factory.factorymethod;

public class Benz implements Car
{
@Override
public void run()
{
System.out.println("奔驰出发");
}
}

package com.match.factory.factorymethod;

public class Byd implements Car
{
@Override
public void run()
{
System.out.println("比亚迪出发");
}
}

工厂接口:

  • 抽象工厂角色: 这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。
package com.match.factory.factorymethod;
/**
* 工厂方法接口
* @author Match
*
*/
public interface CarFactory
{
Car createCar();
}

具体工厂类:

  • 具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。
package com.match.factory.factorymethod;

public class AudiFactory implements CarFactory
{
@Override
public Car createCar()
{
return new Audi();
}
}

package com.match.factory.factorymethod;

public class BenzFactory implements CarFactory
{
@Override
public Car createCar()
{
return new Benz();
}
}

package com.match.factory.factorymethod;

public class BydFactory implements CarFactory
{
@Override
public Car createCar()
{
return new Byd();
}
}

测试代码:

package com.match.factory.factorymethod;

public class Client
{
public static void main(String[] args)
{
Car c1 = new AudiFactory().createCar();
Car c2 = new BydFactory().createCar();
Car c3 = new BenzFactory().createCar();
c1.run();
c2.run();
c3.run();
}
}

抽象工厂模式

类图

代码

产品接口及具体产品类:

  • 抽象产品角色:它是具体产品继承的父类或者是实现的接口。
  • 具体产品角色:具体工厂角色所创建的对象就是此角色的实例。
//引擎
package com.match.factory.abstractfactory;

public interface Engine
{
void run();
void start();
}
class LuxuryEngine implements Engine
{

@Override
public void run()
{
System.out.println("转的快!");
}

@Override
public void start()
{
System.out.println("启动快!可以自动启停!");
}

}
class LowEngine implements Engine
{

@Override
public void run()
{
System.out.println("转的慢!");
}

@Override
public void start()
{
System.out.println("启动慢!");
}

}

//座椅
package com.match.factory.abstractfactory;

public interface Seat
{
void message();
}
class LuxurySeat implements Seat
{
@Override
public void message()
{
System.out.println("可以自动按摩!");
}
}
class LowSeat implements Seat
{
@Override
public void message()
{
System.out.println("不能按摩!");
}
}

//轮胎
package com.match.factory.abstractfactory;

public interface Tyre
{
void revolve();
}
class LuxuryTyre implements Tyre
{

@Override
public void revolve()
{
System.out.println("旋转不磨损!");
}

}
class LowTyre implements Tyre
{

@Override
public void revolve()
{
System.out.println("旋转磨损快!");
}

}

工厂接口:

  • 抽象工厂角色: 这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。
package com.match.factory.abstractfactory;

public interface CarFactory
{
Engine createEngine();
Seat createSeat();
Tyre createTyre();
}

具体工厂类:

  • 具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。
//高级工厂
package com.match.factory.abstractfactory;

public class LuxuryCarFactory implements CarFactory
{
@Override
public Engine createEngine()
{
return new LuxuryEngine();
}
@Override
public Seat createSeat()
{
return new LuxurySeat();
}
@Override
public Tyre createTyre()
{
return new LuxuryTyre();
}
}

//低级工厂
package com.match.factory.abstractfactory;

public class LowCarFactory implements CarFactory
{
@Override
public Engine createEngine()
{
return new LowEngine();
}
@Override
public Seat createSeat()
{
return new LowSeat();
}
@Override
public Tyre createTyre()
{
return new LowTyre();
}
}

抽象工厂与工厂方法的区别

两个慨念:

  • 产品等级结构:产品等级结构即产品的继承结构。
    如一个抽象类是汽车,其子类有奥迪汽车、比亚迪汽车、奔驰汽车,则抽象汽车与具体品牌的汽车之间构成了一个产品等级结构,抽象汽车是父类,而具体品牌的汽车其子类。
  • 产品族:在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品。
    如高配车工厂生产的高级引擎、高级座椅、高级轮胎,高级引擎位于引擎产品等级结构中,高级座椅位于座椅产品等级结构中,高级轮胎位于轮胎产品等级结构中。高级引擎、高级座椅、高级轮胎构成了一个产品族。

抽象工厂模式是工厂方法模式的升级版本,他用来创建一组相关或者相互依赖的对象。他与工厂方法模式的区别就在于,工厂方法模式针对的是一个产品等级结构;而抽象工厂模式则是针对的多个产品等级结构。在编程中,通常一个产品结构,表现为一个接口或者抽象类,也就是说,工厂方法模式提供的所有产品都是衍生自同一个接口或抽象类,而抽象工厂模式所提供的产品则是衍生自不同的接口或抽象类。

总结

无论是简单工厂模式,工厂方法模式,还是抽象工厂模式,他们都属于工厂模式,在形式和特点上也是极为相似的,他们的最终目的都是为了解耦。所以,在使用工厂模式时,最应该关心降低耦合度的目的是否达到了。

简而言之,没有工厂的时候什么都要亲力亲为很麻烦,耦合度十分高,于是有了简单工厂。可简单工厂耦合度还是高所以有了工厂方法。耦合度问题是解决,突然又发现,工厂方法只能生产一种东西,也可以称之为一类东西,比如我这工厂只能造引擎,轮胎我造不了。于是就有了抽象工厂,抽象工厂就牛叉了,引擎我能造,轮胎我也能造,最后把车都给你造出来了,所有抽象工厂又叫工厂的工厂。

加载评论框需要翻墙